//=================================================================================//
// manage the database for CEM simulation
// Author : Wang Yong
// Date   : 2020.10.28
//=================================================================================//
#include <algorithm>
#include <fstream>
#include "DataBase.h"
#include <QtWidgets/QMessageBox>
using namespace tinyxml2;
using namespace std;

DataBase::DataBase()
{
    m_pSymSet[0] = 0;
    m_pSymSet[1] = 0;
    m_pSymSet[2] = 0;

    m_vMedi.emplace_back();
    m_vMedi.back().sName = "PEC";
    m_vMedi.emplace_back();
    m_vMedi.back().sName = "Background";
}

bool DataBase::fn_LoadFile(const std::string &sName)
{
    XMLDocument doc;
    if (XML_SUCCESS != doc.LoadFile(sName.c_str())) {
        return false;
    }

    auto pRoot = doc.RootElement();
    if (!pRoot) {
        return false;
    }
    // load the frequency parameter
    if (!fn_LoadFreqPara(pRoot)) {
        return false;
    }
    // load material parameter
    if (!fn_LoadMediPara(pRoot)) {
        return false;
    }
    // load domain setting parameter
    if (!fn_LoadDomaPara(pRoot)) {
        return false;
    }
    // load symmetric parameter
    fn_LoadSymmetry(pRoot);

    // load post setting parameter
    fn_LoadPostPara(pRoot);

    // load parameter for all solver
    fn_LoadSolvPara(pRoot);

    // load voltage parameter
    fn_LoadVoltPara(pRoot);

    return true;
}

bool DataBase::fn_LoadNear(const std::string &sPath)
{
    int pNum[3];

    for (auto &near : m_vNear) {
        near.vR.clear();
        near.vvTria.clear();
        near.vvQuad.clear();

        if (near.bUserType) continue;

        string sName = sPath + "/post/" + near.sName;
        ifstream fp(sName, ios::in | ios::binary);
        if (!fp.is_open()) {
            return false;
        }
        fp.read(reinterpret_cast<char*>(pNum), sizeof(int) * 3);
        if (pNum[0] > 0) {
            near.vR.resize(pNum[0]);
            fp.read(reinterpret_cast<char*>(&near.vR[0]), sizeof(Node) * near.vR.size());
        }
        if (pNum[1] > 0) near.vvTria.resize(pNum[1], vector<int>(3));
        if (pNum[2] > 0) near.vvQuad.resize(pNum[2], vector<int>(4));
        for (auto &v : near.vvTria) {
            fp.read(reinterpret_cast<char*>(&v[0]), sizeof(int) * 3);
        }
        for (auto &v : near.vvQuad) {
            fp.read(reinterpret_cast<char*>(&v[0]), sizeof(int) * 4);
        }
        fp.close();
    }
    return true;
}

bool DataBase::fn_WriteXML(const std::string &sName)
{
    XMLDocument doc;
    const char *head = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

    doc.Parse(head);
    auto pRoot = doc.NewElement("CEMS");
    auto pFreq = doc.NewElement("Frequency");
    pFreq->SetAttribute("Unit", m_freqSet.sFreqUnit.c_str());
    pFreq->SetAttribute("AnalysisFreq", m_freqSet.dFreq0);
    if (m_freqSet.iNumFreq > 0) {
        pFreq->SetAttribute("MinFreq", m_freqSet.dMinFreq);
        pFreq->SetAttribute("MaxFreq", m_freqSet.dMaxFreq);
        pFreq->SetAttribute("NumFreq", m_freqSet.iNumFreq);
        pFreq->SetAttribute("SweepType", m_freqSet.sSwpType.c_str()); // Discrete, Interpolate, Fast
    }
    pRoot->InsertEndChild(pFreq);

    auto pSymm = doc.NewElement("Symmetry");
    pSymm->SetAttribute("YOZ", m_pSymSet[0]);
    pSymm->SetAttribute("XOZ", m_pSymSet[1]);
    pSymm->SetAttribute("XOY", m_pSymSet[2]);
    pRoot->InsertEndChild(pSymm);

    auto pMedi = doc.NewElement("Material");
    pMedi->SetAttribute("Count", static_cast<int>(m_vMedi.size()-1));
    for (unsigned i = 1; i < m_vMedi.size(); ++i) {
        auto pSon = doc.NewElement(m_vMedi[i].sName.c_str());
        pSon->SetAttribute("ID", i);
        pSon->SetAttribute("Tensor", "false");
        pSon->SetAttribute("Epsilon", m_vMedi[i].dEpsr);
        pSon->SetAttribute("tanE",  m_vMedi[i].dTanE);
        pSon->SetAttribute("Mu",    m_vMedi[i].dMiur);
        pSon->SetAttribute("tanM",  m_vMedi[i].dTanM);
        pSon->SetAttribute("Sigma", m_vMedi[i].dSgma);
        pMedi->InsertEndChild(pSon);
    }
    pRoot->InsertEndChild(pMedi);

    auto pPost = doc.NewElement("PostSet");
    auto pFar = doc.NewElement("FarField");
    pFar->SetAttribute("Count", static_cast<int>(m_vFars.size()));
    for (auto &far : m_vFars) {
        auto pSon = doc.NewElement(far.sName.c_str());
        pSon->SetAttribute("NumPhi", far.iNumPh);
        pSon->SetAttribute("MinPhi", far.dMinPh);
        pSon->SetAttribute("MaxPhi", far.dMaxPh);
        pSon->SetAttribute("NumTheta", far.iNumTh);
        pSon->SetAttribute("MinTheta", far.dMinTh);
        pSon->SetAttribute("MaxTheta", far.dMaxTh);
        pFar->InsertEndChild(pSon);
    }
    pPost->InsertEndChild(pFar);

    auto pNear = doc.NewElement("NearField");
    if (!m_vNear.empty()) {
        pNear->SetAttribute("Setup", "true");
    } else {
        pNear->SetAttribute("Setup", "false");
    }
    pNear->SetAttribute("Count", static_cast<int>(m_vNear.size()));
    for (auto &near : m_vNear) {
        auto pSon = doc.NewElement(near.sName.c_str());
        if (near.bUserType) {
            pSon->SetAttribute("UseMesh", "false");
            pSon->SetAttribute("Xmin", near.dMinX);
            pSon->SetAttribute("Xmax", near.dMaxX);
            pSon->SetAttribute("dx", near.dX);
            pSon->SetAttribute("Ymin", near.dMinY);
            pSon->SetAttribute("Ymax", near.dMaxY);
            pSon->SetAttribute("dy", near.dY);
            pSon->SetAttribute("Zmin", near.dMinZ);
            pSon->SetAttribute("Zmax", near.dMaxZ);
            pSon->SetAttribute("dz", near.dZ);
        } else {
            pSon->SetAttribute("UseMesh", "true");
            pSon->SetAttribute("File", near.sFile.c_str());
        }
        pNear->InsertEndChild(pSon);
    }
    pPost->InsertEndChild(pNear);
    // output current setting
    auto pCurr = doc.NewElement("Current");
    if (m_bCalcCurr) {
        pCurr->SetAttribute("Setup", "true");
    } else {
        pCurr->SetAttribute("Setup", "false");
    }
    pPost->InsertEndChild(pCurr);
    pRoot->InsertEndChild(pPost);

    // output the voltage
    int iNumGroup;
    auto pVolt = doc.NewElement("Voltage");
    pVolt->SetAttribute("Count", fn_GetSourceNum());
    for (auto &src : m_vWave) {
        auto pSrc = doc.NewElement(src.sName.c_str());
        iNumGroup = src.vMag.size();
        pSrc->SetAttribute("Group", iNumGroup);
        for (auto i = 0; i < iNumGroup; ++i) {
            auto pVal = doc.NewElement("Value");
            pVal->SetAttribute("Mag", src.vMag[i]);
            pVal->SetAttribute("Pha", src.vPha[i]);
            pSrc->InsertEndChild(pVal);
        }
        pVolt->InsertEndChild(pSrc);
    }
    for (auto &src : m_vWGap) {
        auto pSrc = doc.NewElement(src.sName.c_str());
        iNumGroup = src.vMag.size();
        pSrc->SetAttribute("Group", iNumGroup);
        for (auto i = 0; i < iNumGroup; ++i) {
            auto pVal = doc.NewElement("Value");
            pVal->SetAttribute("Mag", src.vMag[i]);
            pVal->SetAttribute("Pha", src.vPha[i]);
            pSrc->InsertEndChild(pVal);
        }
        pVolt->InsertEndChild(pSrc);
    }
    for (auto &src : m_vLump) {
        auto pSrc = doc.NewElement(src.sName.c_str());
        iNumGroup = src.vMag.size();
        pSrc->SetAttribute("Group", iNumGroup);
        for (auto i = 0; i < iNumGroup; ++i) {
            auto pVal = doc.NewElement("Value");
            pVal->SetAttribute("Mag", src.vMag[i]);
            pVal->SetAttribute("Pha", src.vPha[i]);
            pSrc->InsertEndChild(pVal);
        }
        pVolt->InsertEndChild(pSrc);
    }
    for (auto &src : m_vPort) {
        auto pSrc = doc.NewElement(src.sName.c_str());
        iNumGroup = src.vMag.size();
        pSrc->SetAttribute("Group", iNumGroup);
        for (auto i = 0; i < iNumGroup; ++i) {
            auto pVal = doc.NewElement("Value");
            pVal->SetAttribute("Mag", src.vMag[i]);
            pVal->SetAttribute("Pha", src.vPha[i]);
            pSrc->InsertEndChild(pVal);
        }
        pVolt->InsertEndChild(pSrc);
    }
    for (auto &src : m_vEqui) {
        auto pSrc = doc.NewElement(src.sName.c_str());
        iNumGroup = src.vMag.size();
        pSrc->SetAttribute("Group", iNumGroup);
        for (auto i = 0; i < iNumGroup; ++i) {
            auto pVal = doc.NewElement("Value");
            pVal->SetAttribute("Mag", src.vMag[i]);
            pVal->SetAttribute("Pha", src.vPha[i]);
            pSrc->InsertEndChild(pVal);
        }
        pVolt->InsertEndChild(pSrc);
    }
    pRoot->InsertEndChild(pVolt);

    auto pSolvr = doc.NewElement("Solver");
    pSolvr->SetAttribute("Parallel", "true");
    pSolvr->SetAttribute("Mpiexe", "C:/program file/MPICH2/bin/mpiexec");
    pSolvr->SetAttribute("NumCore", 4);
    pSolvr->SetAttribute("Integration", m_solvSet.sAccuracy.c_str());    // Fine, Normal, Coarse
    pRoot->InsertEndChild(pSolvr);

    auto pDoma = doc.NewElement("Domain");
    pDoma->SetAttribute("Count", 1);
    auto pMod = doc.NewElement("Model");
    pMod->SetAttribute("ModelName", "model");

    //pMod->SetAttribute("Method", m_Config.sSolver.c_str());
    pMod->SetAttribute("MeshFile", m_sMeshName.c_str());
    if (m_solvSet.iAlgType == ALG_MoM) {
        pMod->SetAttribute("Method", "MoM");
        auto pMoM = doc.NewElement("SetMoM");
        if (m_solvSet.bHobMoM) {
            pMoM->SetAttribute("UseHOB", "true");
        } else {
            pMoM->SetAttribute("UseHOB", "false");
        }
        pMod->InsertEndChild(pMoM);
    } else if (m_solvSet.iAlgType == ALG_MLFMA) {
        pMod->SetAttribute("Method", "MLFMA");
        auto pMLFMA = doc.NewElement("SetMLFMA");
        pMLFMA->SetAttribute("MaxIterStep", m_solvSet.iFmmIterNum);
        pMLFMA->SetAttribute("MaxIterErr", m_solvSet.dFmmIterErr);
        pMLFMA->SetAttribute("IterMethod", m_solvSet.sFmmItrType.c_str());
        pMLFMA->SetAttribute("PreCondition", m_solvSet.sFmmPreCond.c_str());
        pMLFMA->SetAttribute("IERatio", m_solvSet.dFmmIERatio);
        pMLFMA->SetAttribute("CubeSize", m_solvSet.dFmmBoxSize);
        pMLFMA->SetAttribute("SpeedFar", "true");
        pMLFMA->SetAttribute("SpeedNear", "true");
        pMod->InsertEndChild(pMLFMA);
    } else if (m_solvSet.iAlgType == ALG_FEM) {
        pMod->SetAttribute("Method", "FEM");
        auto pFEM = doc.NewElement("SetFEM");
        if (m_solvSet.bHobFEM) {
            pFEM->SetAttribute("Order", 2);
        } else {
            pFEM->SetAttribute("Order", 1);
        }
        pFEM->SetAttribute("SolverType", m_solvSet.sFemSolver.c_str()); // Direct, Iteration, DDM
        pFEM->SetAttribute("MaxIterNum", m_solvSet.iFemMaxIterNum);
        pFEM->SetAttribute("MaxIterErr", m_solvSet.dFemIterErr);
        // parameter for eigen mode
        if (m_solvSet.bEigMode) {
            pFEM->SetAttribute("SolutionType", "Eigen");
            pFEM->SetAttribute("EigModeNum", m_solvSet.iEigModeNum);
            pFEM->SetAttribute("EigMinFreq", m_solvSet.dEigMinFreq);
        } else {
            pFEM->SetAttribute("SolutionType", "Driven");
        }
        // parameter for adaptive mesh
        if (m_solvSet.bAdaptMsh) {
            pFEM->SetAttribute("AdaptMinStep", m_solvSet.iAdapMinNum);
            pFEM->SetAttribute("AdaptMaxStep", m_solvSet.iAdapMaxNum);
            pFEM->SetAttribute("AdaptMinPass", m_solvSet.iAdaPassNum);
            pFEM->SetAttribute("AdaptDeltaSp", m_solvSet.dAdaptDelta);
            pFEM->SetAttribute("AdaptMeshRatio", m_solvSet.dAdaptRatio);
        }
        pFEM->SetAttribute("OutBoundary", m_solvSet.sBoundary.c_str());
        if (m_solvSet.bMetalIn) {
            pFEM->SetAttribute("MetalInside", "true");
        }else {
            pFEM->SetAttribute("MetalInside", "false");
        }
        pMod->InsertEndChild(pFEM);
    }

    if (!m_vWave.empty()) {
        auto pWave = doc.NewElement("PlaneWave");
        pWave->SetAttribute("Count", static_cast<int>(m_vWave.size()));
        for (auto &wave : m_vWave) {
            auto pSon = doc.NewElement(wave.sName.c_str());
            pSon->SetAttribute("NumPhi", wave.iNumPh);
            pSon->SetAttribute("MinPhi", wave.dMinPh);
            pSon->SetAttribute("MaxPhi", wave.dMaxPh);
            pSon->SetAttribute("NumTheta", wave.iNumTh);
            pSon->SetAttribute("MinTheta", wave.dMinTh);
            pSon->SetAttribute("MaxTheta", wave.dMaxTh);
            pSon->SetAttribute("PolarAngle", wave.dPolar);
            pSon->SetAttribute("Rotation", wave.iRot);
            pSon->SetAttribute("AxisRatio", wave.dOAR);
            pWave->InsertEndChild(pSon);
        }
        pMod->InsertEndChild(pWave);
    }

    if (!m_vWGap.empty()) {
        auto pWire = doc.NewElement("Wireport");
        pWire->SetAttribute("Count", static_cast<int>(m_vWGap.size()));
        for (auto &wgap : m_vWGap) {
            auto pSon = doc.NewElement(wgap.sName.c_str());
            pSon->SetAttribute("X", wgap.Oc.x);
            pSon->SetAttribute("Y", wgap.Oc.y);
            pSon->SetAttribute("Z", wgap.Oc.z);
            pSon->SetAttribute("Ex", wgap.ei.x);
            pSon->SetAttribute("Ey", wgap.ei.y);
            pSon->SetAttribute("Ez", wgap.ei.z);
            pSon->SetAttribute("Z0", wgap.z0);
            pWire->InsertEndChild(pSon);
        }
        pMod->InsertEndChild(pWire);
    }

    if (!m_vLump.empty()) {
        auto pLump = doc.NewElement("Lumpport");
        pLump->SetAttribute("Count", static_cast<int>(m_vLump.size()));
        for (auto &lump : m_vLump) {
            auto pSon = doc.NewElement(lump.sName.c_str());
            pSon->SetAttribute("X", lump.Oc.x);
            pSon->SetAttribute("Y", lump.Oc.y);
            pSon->SetAttribute("Z", lump.Oc.z);
            pSon->SetAttribute("Ex", lump.ei.x);
            pSon->SetAttribute("Ey", lump.ei.y);
            pSon->SetAttribute("Ez", lump.ei.z);
            pSon->SetAttribute("Tx", lump.norm.x);
            pSon->SetAttribute("Ty", lump.norm.y);
            pSon->SetAttribute("Tz", lump.norm.z);
            pSon->SetAttribute("Width", lump.dWidth);
            pSon->SetAttribute("Height", lump.dHeigh);
            pSon->SetAttribute("Z0", lump.z0);
            pLump->InsertEndChild(pSon);
        }
        pMod->InsertEndChild(pLump);
    }

    if (!m_vPort.empty()) {
        auto pPort = doc.NewElement("Waveport");
        pPort->SetAttribute("Count", static_cast<int>(m_vPort.size()));
        for (auto &port : m_vPort) {
            if (port.sType == "Circular") {
                port.n = 1;
            } else {
                port.n = 0;
            }
            auto pSon = doc.NewElement(port.sName.c_str());
            pSon->SetAttribute("Type", port.sType.c_str());
            pSon->SetAttribute("BoundID", -1);
            pSon->SetAttribute("X", port.Oc.x);
            pSon->SetAttribute("Y", port.Oc.y);
            pSon->SetAttribute("Z", port.Oc.z);
            pSon->SetAttribute("Ex", port.ei.x);
            pSon->SetAttribute("Ey", port.ei.y);
            pSon->SetAttribute("Ez", port.ei.z);
            pSon->SetAttribute("Tx", port.ai.x);
            pSon->SetAttribute("Ty", port.ai.y);
            pSon->SetAttribute("Tz", port.ai.z);
            pSon->SetAttribute("a", port.a);
            pSon->SetAttribute("b", port.b);
            pSon->SetAttribute("Mode", port.sMode.c_str());
            pSon->SetAttribute("m", port.m);
            pSon->SetAttribute("n", port.n);
            pSon->SetAttribute("Z0", port.z0);
            pPort->InsertEndChild(pSon);
        }
        pMod->InsertEndChild(pPort);
    }
    // output external source
    if (!m_vEqui.empty()) {
        auto pEqui = doc.NewElement("EquivSrc");
        pEqui->SetAttribute("Count", static_cast<int>(m_vEqui.size()));
        for (auto &equi : m_vEqui) {
            auto pSon = doc.NewElement(equi.sName.c_str());
            pSon->SetAttribute("File", equi.sFile.c_str());
            pSon->SetAttribute("X", equi.Oc.x);
            pSon->SetAttribute("Y", equi.Oc.y);
            pSon->SetAttribute("Z", equi.Oc.z);
            pSon->SetAttribute("Theta", equi.theta);
            pSon->SetAttribute("Phi", equi.phi);
            pSon->SetAttribute("Alpha", equi.alpha);
            pEqui->InsertEndChild(pSon);
        }
        pMod->InsertEndChild(pEqui);
    }
    pDoma->InsertEndChild(pMod);
    pRoot->InsertEndChild(pDoma);

    doc.InsertEndChild(pRoot);

    // get the absolute file name
    std::string fname = sName + ".xml";
    if (doc.SaveFile(fname.c_str()) == XML_SUCCESS) {
        return true;
    } else {
        return false;
    }
}

bool DataBase::fn_LoadMesh(const std::string &sName)
{
    auto i = sName.find_last_of(".");
    string sType = sName.substr(i);
    if (sType == ".tet") {
        return fn_LoadTet(sName);
    } else if(sType == ".gdm"){
        return fn_LoadGdm(sName);
    } else if (sType == ".ocm") {
        return fn_LoadOcm(sName);
    } else {
        return false;
    }

}

bool DataBase::fn_SaveMesh(const std::string &sPath)
{
    if (m_sMeshName.empty()) {
        return true;
    }

    if (m_solvSet.iAlgType == ALG_FEM) {
        std::string sMesh = sPath + m_sMeshName + ".tet";
        return fn_SaveTet(sMesh);
    } else {
        std::string sMesh = sPath + m_sMeshName + ".gdm";
        return fn_SaveGdm(sMesh);
    }
}

void DataBase::fn_SaveNear(const std::string &sPath)
{
    int pNum[3];

    for (auto &near : m_vNear) {
        if (near.bUserType) continue;

        string sName = sPath + "/post/" + near.sName;
        ofstream fp(sName, ios::out | ios::binary);
        pNum[0] = near.vR.size();
        pNum[1] = near.vvTria.size();
        pNum[2] = near.vvQuad.size();
        fp.write(reinterpret_cast<char*>(pNum), sizeof(int) * 3);
        fp.write(reinterpret_cast<char*>(&near.vR[0]), sizeof(Node) * near.vR.size());
        for (auto &v : near.vvTria) {
            fp.write(reinterpret_cast<char*>(&v[0]), sizeof(int) * 3);
        }
        for (auto &v : near.vvQuad) {
            fp.write(reinterpret_cast<char*>(&v[0]), sizeof(int) * 4);
        }
        fp.close();
    }
}

bool DataBase::fn_LoadGdm(const std::string &sName)
{
    std::ifstream fp(sName);
    if (!fp.is_open()) {
        return false;
    }

    unsigned long iNodeNum, iWireNum, iTriaNum, iQuadNum;
    unsigned int iBoudNum;
    int *pV = nullptr;
    fp >> iNodeNum >> iWireNum >> iTriaNum >> iQuadNum;
    fp >> iBoudNum;

    m_surf.vvBoud.clear();
    m_surf.vR.clear();
    m_surf.vvWire.clear();
    m_surf.vvTria.clear();
    m_surf.vvQuad.clear();
    m_surf.vRadius.clear();

    if (iBoudNum > 0) m_surf.vvBoud.assign(iBoudNum, std::vector<int>(3));
    if (iNodeNum > 0) m_surf.vR.resize(iNodeNum);
    if (iWireNum > 0) m_surf.vRadius.resize(iWireNum);
    if (iWireNum > 0) m_surf.vvWire.assign(iWireNum, std::vector<int>(3));
    if (iTriaNum > 0) m_surf.vvTria.assign(iTriaNum, std::vector<int>(4));
    if (iQuadNum > 0) m_surf.vvQuad.assign(iQuadNum, std::vector<int>(5));
    for (auto &boud : m_surf.vvBoud) {
        fp >> boud[0] >> boud[1] >> boud[2];
    }
    for (auto &r : m_surf.vR) {
        fp >> r.x >> r.y >> r.z;
    }
    for (unsigned i = 0; i < iWireNum; ++i) {
        fp >> m_surf.vvWire[i][0] >> m_surf.vvWire[i][1] >> m_surf.vRadius[i] >> m_surf.vvWire[i][2];
    }
    for (auto &v : m_surf.vvTria) {
        fp >> v[0] >> v[1] >> v[2] >> v[3];
    }
    for (auto &v : m_surf.vvQuad) {
        fp >> v[0] >> v[1] >> v[2] >> v[3] >> v[4];
    }
    fp.close();

    return true;
}

bool DataBase::fn_LoadTet(const std::string &sName)
{
    std::ifstream fp(sName);
    if (!fp.is_open()) {
        return false;
    }

    unsigned long iNodeNum,iTetrNum;
    unsigned int iBoudNum;
    fp >> iNodeNum >> iTetrNum >> iBoudNum;

    m_volu.vBoud.clear();
    m_volu.vR.clear();
    m_volu.vvTetr.clear();

    if (iBoudNum > 0) m_volu.vBoud.resize(iBoudNum);
    if (iNodeNum > 0) m_volu.vR.resize(iNodeNum);
    if (iTetrNum > 0) m_volu.vvTetr.assign(iTetrNum, std::vector<int>(5));
    for (auto &r : m_volu.vR) {
        fp >> r.x >> r.y >> r.z;
    }
    for (auto &v : m_volu.vvTetr) {
        fp >> v[0] >> v[1] >> v[2] >> v[3] >> v[4];
    }
    for (auto &boud : m_volu.vBoud) {
        fp >> boud.sType >> boud.iID >> boud.iTriaNum;
        boud.vvTria.assign(boud.iTriaNum, std::vector<int>(4));
        for (auto &v : boud.vvTria) {
            fp >> v[0] >> v[1] >> v[2] >> v[3];
        }
    }
    fp.close();

    return true;
}

bool DataBase::fn_LoadOcm(const std::string& sName)
{
    std::ifstream fp(sName);
    if (!fp.is_open()) {
        return false;
    }
    m_surf.vvBoud.clear();
    m_surf.vR.clear();
    m_surf.vvWire.clear();
    m_surf.vvTria.clear();
    m_surf.vvQuad.clear();
    m_surf.vRadius.clear();

    m_surf.vvBoud.assign(1, std::vector<int>(3));
    m_surf.vvBoud[0][0] = 1;
    m_surf.vvBoud[0][1] = 0;
    m_surf.vvBoud[0][2] = 0;

    unsigned long iNodeNum, iElemNum, iTriaNum, iQuadNum;
    string sKeyWord, sUnit, sType;
    getline(fp, sKeyWord);
    fp >> sKeyWord >> iNodeNum;
    fp >> sKeyWord >> iElemNum;
    fp >> sKeyWord >> iTriaNum;
    fp >> sKeyWord >> iQuadNum;
    fp >> sKeyWord >> sUnit;
    getline(fp, sKeyWord);
    getline(fp, sKeyWord);
    while (fp >> sKeyWord >> sType) {
        if (sKeyWord == "Node") break;
    }
    // load the node
    if (iNodeNum > 0) m_surf.vR.resize(iNodeNum);
    double dUnit = 1.0;
    if (sUnit == "nm") {
        dUnit = 0.001;
    } else if (sUnit == "mm") {
        dUnit = 1000.0;
    } else if (sUnit == "m") {
        dUnit = 1.0e6;
    }
    int i;
    for (auto& r : m_surf.vR) {
        fp >> i >> r.x >> r.y >> r.z;
        r.x *= dUnit;
        r.y *= dUnit;
        r.z *= dUnit;
    }
    getline(fp, sKeyWord);

    // load element
    while (fp >> sKeyWord >> sType) {
        if (sKeyWord == "Element") break;
    }
    fp.clear();
    int iType, v[8];
    double dSigma;
    auto tria = std::vector<int>(4, 0);
    auto quad = std::vector<int>(5, 0);
    while (fp >> sKeyWord >> dSigma >> sType >> iElemNum) {
        for (i = 0; i < iElemNum; ++i) {
            fp >> iType;
            for (int j = 0; j < iType; ++j) {
                fp >> v[j];
            }
            if (6 == iType) {
                tria[0] = v[0]; tria[1] = v[2]; tria[2] = v[1];
                m_surf.vvTria.push_back(tria);
                tria[0] = v[3]; tria[1] = v[4]; tria[2] = v[5];
                m_surf.vvTria.push_back(tria);
                quad[0] = v[0]; quad[1] = v[1]; quad[2] = v[4]; quad[3] = v[3];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[1]; quad[1] = v[2]; quad[2] = v[5]; quad[3] = v[4];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[0]; quad[1] = v[3]; quad[2] = v[5]; quad[3] = v[2];
                m_surf.vvQuad.push_back(quad);
            } else {
                quad[0] = v[0]; quad[1] = v[3]; quad[2] = v[2]; quad[3] = v[1];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[4]; quad[1] = v[5]; quad[2] = v[6]; quad[3] = v[7];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[0]; quad[1] = v[1]; quad[2] = v[5]; quad[3] = v[4];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[1]; quad[1] = v[2]; quad[2] = v[6]; quad[3] = v[5];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[2]; quad[1] = v[3]; quad[2] = v[7]; quad[3] = v[6];
                m_surf.vvQuad.push_back(quad);
                quad[0] = v[0]; quad[1] = v[4]; quad[2] = v[7]; quad[3] = v[3];
                m_surf.vvQuad.push_back(quad);
            }
        }
    }
    fp.close();

    return true;
}

bool DataBase::fn_SaveGdm(const std::string &sName)
{
    std::ofstream fp(sName.c_str());
    if (!fp.is_open()) {
        return false;
    }

    fp << m_surf.vR.size() << "  " << m_surf.vvWire.size() << "  "
       << m_surf.vvTria.size() << "  " << m_surf.vvQuad.size() << std::endl;
    fp << m_surf.vvBoud.size() << std::endl;
    for (auto &boud : m_surf.vvBoud) {
        fp << boud[0] << "  " << boud[1] << "  " << boud[2] << std::endl;
    }
    for (auto &r : m_surf.vR) {
        fp << r.x << "  " << r.y << "  " << r.z << std::endl;
    }
    for (auto i = 0; i < m_surf.vvWire.size(); ++i) {
        fp << m_surf.vvWire[i][0] << "  " << m_surf.vvWire[i][1] << "  "
           << m_surf.vRadius[i] << "  " << m_surf.vvWire[i][2] << std::endl;
    }
    for (auto &tria : m_surf.vvTria) {
        fp << tria[0] << "  " << tria[1] << "  " << tria[2] << "  " << tria[3] << std::endl;
    }
    for (auto &quad : m_surf.vvQuad) {
        fp << quad[0] << "  " << quad[1] << "  " << quad[2] << "  " 
           << quad[3] << "  " << quad[4] << std::endl;
    }
    fp.close();

    return true;
}

bool DataBase::fn_SaveTet(const std::string &sName)
{
    std::ofstream fp(sName.c_str());
    if (!fp.is_open()) {
        return false;
    }

    fp << m_volu.vR.size() << "  " << m_volu.vvTetr.size() << "  " << m_volu.vBoud.size() << std::endl;
    for (auto &r : m_volu.vR) {
        fp << r.x << "  " << r.y << "  " << r.z << std::endl;
    }
    for (auto &tetr : m_volu.vvTetr) {
        fp << tetr[0] << "  " << tetr[1] << "  " << tetr[2] << "  "
           << tetr[3] << "  " << tetr[4] << std::endl;
    }
    for (auto &boud : m_volu.vBoud) {
        fp << boud.sType << "  " << boud.iID << "  " << boud.vvTria.size() << std::endl;
        for (auto i = 0; i < boud.vvTria.size(); ++i) {
            fp << boud.vvTria[i][0] << "  " << boud.vvTria[i][1] << "  "
               << boud.vvTria[i][2] << "  " << boud.vvTria[i][3] << std::endl;
        }
    }
    fp.close();
    return true;
}

bool DataBase::fn_ExportGidMsh(const std::string &sName)
{
    ofstream fp(sName);
    if (!fp.is_open()) return false;

    int i;
    if (!m_surf.vR.empty()) {
        bool bNodeOut = false;
        if (!m_surf.vvTria.empty()) {
            fp << "MESH dimension 3 ElemType Triangle Nnode 3" << endl;
            fp << "Coordinates" << endl;
            i = 0;
            for (auto &r : m_surf.vR) {
                ++i;
                fp << i << "  " << r.x << "  " << r.y << "  " << r.z << endl;
            }
            bNodeOut = true;
            fp << "End Coordinates" << endl << endl;
            fp << "Elements" << endl;
            i = 0;
            for (auto &v : m_surf.vvTria) {
                ++i;
                fp << i << "  " << v[0] << "  " << v[1] << "  " << v[2] << endl;
            }
            fp << "End Elements" << endl;
        }
        if (!m_surf.vvQuad.empty()) {
            fp << "MESH dimension 3 ElemType Quadrilateral Nnode 4" << endl;
            fp << "Coordinates" << endl;
            if (!bNodeOut) {
                int n = 0;
                for (auto &r : m_surf.vR) {
                    ++n;
                    fp << n << "  " << r.x << "  " << r.y << "  " << r.z << endl;
                }
                bNodeOut = true;
            }
            fp << "End Coordinates" << endl << endl;
            fp << "Elements" << endl;
            for (auto &v : m_surf.vvQuad) {
                ++i;
                fp << i << "  " << v[0] << "  " << v[1] << "  " << v[2] << "  " << v[3] << endl;
            }
            fp << "End Elements" << endl;
        }
        if (!m_surf.vvWire.empty()) {
            fp << "MESH dimension 3 ElemType Linear Nnode 2" << endl;
            fp << "Coordinates" << endl;
            if (!bNodeOut) {
                int n = 0;
                for (auto &r : m_surf.vR) {
                    ++n;
                    fp << n << "  " << r.x << "  " << r.y << "  " << r.z << endl;
                }
                bNodeOut = true;
            }
            fp << "End Coordinates" << endl << endl;
            fp << "Elements" << endl;
            for (auto &v : m_surf.vvWire) {
                ++i;
                fp << i << "  " << v[0] << "  " << v[1] << endl;
            }
            fp << "End Elements" << endl;
        }
    } else {
        fp << "MESH dimension 3 ElemType Tetrahedra Nnode 4" << endl;
        fp << "Coordinates" << endl;
        i = 0;
        for (auto &r : m_volu.vR) {
            ++i;
            fp << i << "  " << r.x << "  " << r.y << "  " << r.z << endl;
        }
        fp << "End Coordinates" << endl << endl;
        fp << "Elements" << endl;
        i = 0;
        for (auto &v : m_volu.vvTetr) {
            ++i;
            fp << i << "  " << v[0] << "  " << v[1] << "  " << v[2] << "  " << v[3] << endl;
        }
        fp << "End Elements" << endl;
    }

    fp.close();

    return true;
}

bool DataBase::fn_OutNearPoint(const std::string &sName)
{
    if (m_vNear.empty()) return true;

    string sFile = sName + ".vgeo";

    ofstream fp(sFile);
    if (!fp.is_open()) {
        return false;
    }

    for (auto &near : m_vNear) {
        if (near.bUserType) {
            int iNumX = 1, iNumY = 1, iNumZ = 1;
            if (fabs(near.dX) > 1.0e-8) iNumX = (near.dMaxX - near.dMinX) / near.dX + 1;
            if (fabs(near.dY) > 1.0e-8) iNumY = (near.dMaxY - near.dMinY) / near.dY + 1;
            if (fabs(near.dZ) > 1.0e-8) iNumZ = (near.dMaxZ - near.dMinZ) / near.dZ + 1;
            fp << near.sName << "  " << iNumX * iNumY * iNumZ << endl;
            int j, k;
            Node r;
            for (int i = 0; i < iNumZ; ++i) {
                r.z = near.dMinZ + i * near.dZ;
                for (j = 0; j < iNumY; ++j) {
                    r.y = near.dMinY + j * near.dY;
                    for (k = 0; k < iNumX; ++k) {
                        r.x = near.dMinX + k * near.dX;
                        fp << r.x << "  " << r.y << "  " << r.z << endl;
                    }
                }
            }
        } else {
            fp << near.sName << "  " << near.vR.size() << endl;
            for (auto &r : near.vR) {
                fp << r.x << "  " << r.y << "  " << r.z << endl;
            }
        }
    }
    return true;
}

void DataBase::fn_UpdateRadius(double &dRad)
{
    dRad /= 1000.0;
    std::fill(m_surf.vRadius.begin(), m_surf.vRadius.end(), dRad);
}

int  DataBase::fn_GetSourceNum()
{
    int iNum = int(m_vWave.size() + m_vWGap.size() + m_vLump.size());
    iNum += m_vPort.size() + m_vEqui.size();

    return iNum;
}

int DataBase::fn_GetPortNum()
{
    return (m_vWGap.size() + m_vLump.size() + m_vPort.size());
}

void DataBase::fn_RemoveMedi(const std::string &sName)
{
    auto itr = m_vMedi.begin();
    while (itr != m_vMedi.end()) {
        if (itr->sName == sName) {
            m_vMedi.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemoveFars(const std::string &sName)
{
    auto itr = m_vFars.begin();
    while (itr != m_vFars.end()) {
        if (itr->sName == sName) {
            m_vFars.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemoveNear(const std::string &sName)
{
    auto itr = m_vNear.begin();
    while (itr != m_vNear.end()) {
        if (itr->sName == sName) {
            m_vNear.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemoveWave(const std::string &sName)
{
    auto itr = m_vWave.begin();
    while (itr != m_vWave.end()) {
        if (itr->sName == sName) {
            m_vWave.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemoveWGap(const std::string &sName)
{
    auto itr = m_vWGap.begin();
    while (itr != m_vWGap.end()) {
        if (itr->sName == sName) {
            m_vWGap.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemoveLump(const std::string &sName)
{
    auto itr = m_vLump.begin();
    while (itr != m_vLump.end()) {
        if (itr->sName == sName) {
            m_vLump.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemovePort(const std::string &sName)
{
    auto itr = m_vPort.begin();
    while (itr != m_vPort.end()) {
        if (itr->sName == sName) {
            m_vPort.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_RemoveEqui(const std::string &sName)
{
    auto itr = m_vEqui.begin();
    while (itr != m_vEqui.end()) {
        if (itr->sName == sName) {
            m_vEqui.erase(itr);
            break;
        }
        ++itr;
    }
}

void DataBase::fn_ClearData()
{
    m_freqSet.dFreq0 = 0;
    m_freqSet.iNumFreq = 0;
    m_freqSet.dMinFreq = 0;
    m_freqSet.dMaxFreq = 0;
    m_freqSet.sFreqUnit = "GHz";
    m_freqSet.sSwpType = "Interpolate";

    m_pSymSet[0] = 0;
    m_pSymSet[1] = 0;
    m_pSymSet[2] = 0;
    m_bCalcCurr = false;
    m_sMeshName = "";

    m_surf.vR.clear();
    m_surf.vRadius.clear();
    m_surf.vvBoud.clear();
    m_surf.vvWire.clear();
    m_surf.vvTria.clear();
    m_surf.vvQuad.clear();
    m_volu.vR.clear();
    m_volu.vBoud.clear();
    m_volu.vvTetr.clear();

    m_vMedi.clear();
    m_vWave.clear();
    m_vWGap.clear();
    m_vLump.clear();
    m_vPort.clear();
    m_vEqui.clear();
    m_vFars.clear();
    m_vNear.clear();

    m_vMedi.emplace_back();
    m_vMedi.back().sName = "PEC";
    m_vMedi.emplace_back();
    m_vMedi.back().sName = "Background";
}

bool DataBase::fn_CheckData(QString &sLog)
{
    for (auto& src : m_vWave) {
        if (m_iNumVolt != src.vMag.size()) {
            sLog = "Have not set the voltage of plane wave.";
            return false;
        }
    }
    for (auto& src : m_vWGap) {
        if (m_iNumVolt != src.vMag.size()) {
            sLog = "Have not set the voltage of wire port.";
            return false;
        }
    }
    for (auto& src : m_vLump) {
        if (m_iNumVolt != src.vMag.size()) {
            sLog = "Have not set the voltage of lump port.";
            return false;
        }
    }
    for (auto& src : m_vPort) {
        if (m_iNumVolt != src.vMag.size()) {
            sLog = "Have not set the voltage of waveport.";
            return false;
        }
    }
    for (auto& src : m_vEqui) {
        if (m_iNumVolt != src.vMag.size()) {
            sLog = "Have not set the voltage of equivalent source.";
            return false;
        }
    }

    return true;
}

// load the frequency parameter
bool DataBase::fn_LoadFreqPara(tinyxml2::XMLElement *pRoot)
{
    auto pFreq = pRoot->FirstChildElement("Frequency");
    if (!pFreq) return false;

    m_freqSet.sFreqUnit = pFreq->Attribute("Unit");
    if (m_freqSet.sFreqUnit.empty()) return false;

    auto cVal = pFreq->Attribute("AnalysisFreq");
    if (!cVal) return false;

    m_freqSet.dFreq0 = stod(std::string(cVal));

    // check whether sweep frequency
    
    cVal = pFreq->Attribute("NumFreq");
    if (!cVal) {
        m_freqSet.iNumFreq = 0;
        return true;
    }
    m_freqSet.iNumFreq = stoi(std::string(cVal));

    cVal = pFreq->Attribute("MinFreq");
    if (!cVal) return false;
    m_freqSet.dMinFreq = stod(std::string(cVal));

    cVal = pFreq->Attribute("MaxFreq");
    if (!cVal) return false;
    m_freqSet.dMaxFreq = stod(std::string(cVal));

    m_freqSet.sSwpType = pFreq->Attribute("SweepType");
    if (m_freqSet.sSwpType != "Discrete"    &&
        m_freqSet.sSwpType != "Interpolate" &&
        m_freqSet.sSwpType != "Fast") {
        return false;
    }
    return true;
}

// load material parameter                          
bool DataBase::fn_LoadMediPara(tinyxml2::XMLElement *pRoot)
{
    auto pMedi = pRoot->FirstChildElement("Material");
    if (!pMedi) return false;

    auto cVal = pMedi->Attribute("Count");
    if (!cVal) return false;

    int iNumMedi = stoi(std::string(cVal));
    if (iNumMedi < 1 || iNumMedi > 10000) {   // maximum material number is 10000
        return false;
    }
    m_vMedi.pop_back();
    Material medi;
    std::string sValue;
    auto pNode = pMedi->FirstChildElement();
    for (int i = 0; i < iNumMedi; ++i) {
        medi.sName = pNode->Name();
        cVal = pNode->Attribute("Tensor");
        if (cVal && std::string(cVal) == "true") {
            medi.bTensor = true;
        } else {
            medi.bTensor = false;
            sValue = pNode->Attribute("Epsilon");
            medi.dEpsr = stod(sValue);
            sValue = pNode->Attribute("tanE");
            medi.dTanE = stod(sValue);
            sValue = pNode->Attribute("Mu");
            medi.dMiur = stod(sValue);
            sValue = pNode->Attribute("tanM");
            medi.dTanM = stod(sValue);
            sValue = pNode->Attribute("Sigma");
            medi.dSgma = stod(sValue);
        }
        m_vMedi.push_back(medi);
        pNode = pNode->NextSiblingElement();
    }
    if (m_vMedi.size() < 2) {
        return false;
    }
    return true;
}

// load symmetric parameter                         
bool DataBase::fn_LoadSymmetry(tinyxml2::XMLElement *pRoot)
{
    m_pSymSet[0] = 0;
    m_pSymSet[1] = 0;
    m_pSymSet[2] = 0;
    // load symmetric set
    auto pSym = pRoot->FirstChildElement("Symmetry");
    if (!pSym) {
        return false;
    }

    auto cVal = pSym->Attribute("YOZ");
    if (cVal) {
        m_pSymSet[0] = stoi(std::string(cVal));
    }
    cVal = pSym->Attribute("XOZ");
    if (cVal) {
        m_pSymSet[1] = stoi(std::string(cVal));
    }
    cVal = pSym->Attribute("XOY");
    if (cVal) {
        m_pSymSet[2] = stoi(std::string(cVal));
    }
    return true;
}

// load domain setting parameter                    
bool DataBase::fn_LoadDomaPara(tinyxml2::XMLElement *pRoot)
{
    auto pDoma = pRoot->FirstChildElement("Domain");
    if (!pDoma) {
        return false;
    }
    auto cVal = pDoma->Attribute("Count");
    if (!cVal) {
        return false;
    }
    int iNumDoma = stoi(std::string(cVal));
    if (iNumDoma < 1) {
        return false;
    }

    auto pMode = pDoma->FirstChildElement();
    std::string sValue = pMode->Attribute("Method");
    if (sValue == "MoM") {
        m_solvSet.iAlgType = ALG_MoM;
    } else if (sValue == "MLFMA") {
        m_solvSet.iAlgType = ALG_MLFMA;
    } else if (sValue == "FEM") {
        m_solvSet.iAlgType = ALG_FEM;
    } else if (sValue == "UTD") {
        m_solvSet.iAlgType = ALG_UTD;
    } else {
        return false;
    }
    
    m_sMeshName = pMode->Attribute("MeshFile");
    // load algorithm setting parameter
    fn_LoadAlgoPara(pMode);
    // load plane wave parameter
    fn_LoadPlanWave(pMode);
    // load wire delta parameter
    fn_LoadWirePort(pMode);
    // load lump port parameter
    fn_LoadLumpPort(pMode);
    // load waveport parameter
    fn_LoadWavePort(pMode);
    // load equivalent source
    if (!fn_LoadEquivSrc(pMode)) {
        return false;
    }
    return true;
}

// load post setting parameter                      
bool DataBase::fn_LoadPostPara(tinyxml2::XMLElement *pRoot)
{
    auto pPost = pRoot->FirstChildElement("PostSet");
    if (!pPost) {
        return false;
    }

    auto pNode = pPost->FirstChildElement("FarField");
    if (pNode) {
        std::string sValue = pNode->Attribute("Count");
        m_vFars.resize(stoi(sValue));
        auto pSon = pNode->FirstChildElement();
        for (int i = 0; i < m_vFars.size(); ++i) {
            m_vFars[i].sName = pSon->Name();
            sValue = pSon->Attribute("NumPhi");
            m_vFars[i].iNumPh = stoi(sValue);
            sValue = pSon->Attribute("NumTheta");
            m_vFars[i].iNumTh = stoi(sValue);
            sValue = pSon->Attribute("MinPhi");
            m_vFars[i].dMinPh = stod(sValue);
            sValue = pSon->Attribute("MaxPhi");
            m_vFars[i].dMaxPh = stod(sValue);
            sValue = pSon->Attribute("MinTheta");
            m_vFars[i].dMinTh = stod(sValue);
            sValue = pSon->Attribute("MaxTheta");
            m_vFars[i].dMaxTh = stod(sValue);
            pSon = pSon->NextSiblingElement();
        }
    }

    pNode = pPost->FirstChildElement("NearField");
    if (pNode) {
        std::string sValue = pNode->Attribute("Count");
        m_vNear.resize(stoi(sValue));
        auto pSon = pNode->FirstChildElement();
        for (int i = 0; i < m_vNear.size(); ++i) {
            m_vNear[i].sName = pSon->Name();
            sValue = pSon->Attribute("UseMesh");
            if (sValue == "false") {
                m_vNear[i].bUserType = true;
                sValue = pSon->Attribute("Xmin");
                m_vNear[i].dMinX = stod(sValue);
                sValue = pSon->Attribute("Xmax");
                m_vNear[i].dMaxX = stod(sValue);
                sValue = pSon->Attribute("dx");
                m_vNear[i].dX = stod(sValue);
                sValue = pSon->Attribute("Ymin");
                m_vNear[i].dMinY = stod(sValue);
                sValue = pSon->Attribute("Ymax");
                m_vNear[i].dMaxY = stod(sValue);
                sValue = pSon->Attribute("dy");
                m_vNear[i].dY = stod(sValue);
                sValue = pSon->Attribute("Zmin");
                m_vNear[i].dMinZ = stod(sValue);
                sValue = pSon->Attribute("Zmax");
                m_vNear[i].dMaxZ = stod(sValue);
                sValue = pSon->Attribute("dz");
                m_vNear[i].dZ = stod(sValue);
            } else {
                m_vNear[i].bUserType = false;
                m_vNear[i].sFile = pSon->Attribute("File");
            }
            pSon = pSon->NextSiblingElement();
        }
    }

    pNode = pPost->FirstChildElement("Current");
    m_bCalcCurr = false;
    if (pNode) {
        auto cVal = pNode->Attribute("Setup");
        if (cVal && std::string(cVal) == "true") {
            m_bCalcCurr = true;
        }
    }
    return true;
}

// load voltage parameter                           
void DataBase::fn_LoadVoltPara(tinyxml2::XMLElement *pRoot)
{
    auto pVolt = pRoot->FirstChildElement("Voltage");
    if (!pVolt) return;
    
    auto cVal = pVolt->Attribute("Count");
    if (!cVal) return;

    std::string sName;
    int iNumVolt, n;
    int iNumSrc = stoi(std::string(cVal));
    auto pNode = pVolt->FirstChildElement();
    for (int i = 0; i < iNumSrc; ++i) {
        sName = pNode->Name();
        cVal = pNode->Attribute("Group");
        iNumVolt = stoi(std::string(cVal));
        auto vMag = std::vector<double>(iNumVolt, 1.0);
        auto vPha = std::vector<double>(iNumVolt, 0.0);
        auto pValue = pNode->FirstChildElement();
        for (n = 0; n < iNumVolt; ++n) {
            vMag[n] = stod(std::string(pValue->Attribute("Mag")));
            vPha[n] = stod(std::string(pValue->Attribute("Pha")));
            pValue = pValue->NextSiblingElement();
        }
        fn_SetVoltToSrc(sName, vMag, vPha);
        pNode = pNode->NextSiblingElement();
    }
    fn_SetVoltGroup();
}
                                                    
// load parameter for all solver                    
void DataBase::fn_LoadSolvPara(tinyxml2::XMLElement *pRoot)
{
    auto pSolv = pRoot->FirstChildElement("Solver");
    if (!pSolv) {
        m_solvSet.sAccuracy = "Normal";
        return;
    }
    m_solvSet.sAccuracy = pSolv->Attribute("Integration");
}

// load algorithm setting parameter                 
void DataBase::fn_LoadAlgoPara(tinyxml2::XMLElement *pRoot)
{
    // load MoM set
    auto pAlg = pRoot->FirstChildElement("SetMOM");
    if (pAlg) {
        auto cVal = pAlg->Attribute("UseHOB");
        if (cVal && std::string(cVal) == "true") {
            m_solvSet.bHobMoM = true;
        } else {
            m_solvSet.bHobMoM = false;
        }
    }
    // load MLFMA set
    pAlg = pRoot->FirstChildElement("SetMLFMA");
    if (pAlg) {
        std::string sValue = pAlg->Attribute("MaxIterStep");
        m_solvSet.iFmmIterNum = stoi(sValue);
        sValue = pAlg->Attribute("MaxIterErr");
        m_solvSet.dFmmIterErr = stod(sValue);
        sValue = pAlg->Attribute("CubeSize");
        m_solvSet.dFmmBoxSize = stod(sValue);
        sValue = pAlg->Attribute("IERatio");
        m_solvSet.dFmmIERatio = stod(sValue);
        m_solvSet.sFmmItrType = pAlg->Attribute("IterMethod");
        m_solvSet.sFmmPreCond = pAlg->Attribute("PreCondition");
        
        sValue = pAlg->Attribute("SpeedFar");
        if (sValue == "false") {
            //m_solvSet.bSpeed = false;
        }
        sValue = pAlg->Attribute("SpeedNear");
        if (sValue == "false") {
            //m_solvSet.bSpeedNear = false;
        }
    }

    // load FEM set
    pAlg = pRoot->FirstChildElement("SetFEM");
    if (pAlg) {
        std::string sValue = pAlg->Attribute("Order");
        m_solvSet.bHobFEM = (stoi(sValue) > 1);
        // parameter for solution type
        sValue = pAlg->Attribute("SolutionType");
        if (sValue == "Driven") {
            m_solvSet.bEigMode = false;    // driven mode
        } else {
            m_solvSet.bEigMode = true;
            sValue = pAlg->Attribute("EigModeNum");
            m_solvSet.iEigModeNum = stoi(sValue);
            sValue = pAlg->Attribute("EigMinFreq");
            m_solvSet.dEigMinFreq = stod(sValue);
        }
        // parameter for solver
        m_solvSet.sFemSolver = pAlg->Attribute("SolverType");
        if (m_solvSet.sFemSolver != "Direct") {
            sValue = pAlg->Attribute("MaxIterNum");
            if (sValue.length() > 0) m_solvSet.iFemMaxIterNum = stoi(sValue);
            sValue = pAlg->Attribute("MaxIterErr");
            if (sValue.length() > 0) m_solvSet.dFemIterErr = stod(sValue);
        }
        // parameter for adaptive mesh
        auto ch = pAlg->Attribute("AdaptMinStep");
        if (ch) {
            m_solvSet.bAdaptMsh = true;
            m_solvSet.iAdapMinNum = stoi(string(ch));
            sValue = pAlg->Attribute("AdaptMaxStep");
            m_solvSet.iAdapMaxNum = stoi(sValue);
            sValue = pAlg->Attribute("AdaptMinPass");
            m_solvSet.iAdaPassNum = stoi(sValue);
            sValue = pAlg->Attribute("AdaptDeltaSp");
            m_solvSet.dAdaptDelta = stod(sValue);
            sValue = pAlg->Attribute("AdaptMeshRatio");
            m_solvSet.dAdaptRatio = stod(sValue);
        } else {
            m_solvSet.bAdaptMsh = false;
        }
        auto boud = pAlg->Attribute("OutBoundary");
        if (boud) {
            m_solvSet.sBoundary = std::string(boud);
        } else {
            m_solvSet.sBoundary = "PEC";
        }
        m_solvSet.bMetalIn = false;
        ch = pAlg->Attribute("MetalInside");
        if (ch) {
            if (string(ch) == "true") {
                m_solvSet.bMetalIn = true;
            }
        }
    }
}

// load plane wave parameter                        
void DataBase::fn_LoadPlanWave(tinyxml2::XMLElement *pRoot)
{
    auto pWave = pRoot->FirstChildElement("PlaneWave");
    if (!pWave) {
        return;
    }
    std::string sValue = pWave->Attribute("Count");
    int iNumWave = stoi(sValue);
    if (iNumWave < 1) {
        return;
    }

    m_vWave.resize(iNumWave);
    auto pNode = pWave->FirstChildElement();
    for (int i = 0; i < iNumWave; ++i) {
        m_vWave[i].sName = pNode->Name();
        sValue = pNode->Attribute("NumPhi");
        m_vWave[i].iNumPh = stoi(sValue);
        sValue = pNode->Attribute("MinPhi");
        m_vWave[i].dMinPh = stoi(sValue);
        sValue = pNode->Attribute("MaxPhi");
        m_vWave[i].dMaxPh = stoi(sValue);
        sValue = pNode->Attribute("NumTheta");
        m_vWave[i].iNumTh = stoi(sValue);
        sValue = pNode->Attribute("MinTheta");
        m_vWave[i].dMinTh = stoi(sValue);
        sValue = pNode->Attribute("MaxTheta");
        m_vWave[i].dMaxTh = stoi(sValue);
        sValue = pNode->Attribute("PolarAngle");
        m_vWave[i].dPolar = stod(sValue);
        sValue = pNode->Attribute("Rotation");
        m_vWave[i].iRot = stoi(sValue);
        sValue = pNode->Attribute("AxisRatio");
        m_vWave[i].dOAR = stod(sValue);

        pNode = pNode->NextSiblingElement();
    }
}

// load wire delta parameter                        
void DataBase::fn_LoadWirePort(tinyxml2::XMLElement *pRoot)
{
    auto pWgap = pRoot->FirstChildElement("Wireport");
    if (!pWgap) {
        return;
    }
    std::string sValue = pWgap->Attribute("Count");
    int iNumWGap = stoi(sValue);
    if (iNumWGap < 1) {
        return;
    }
    m_vWGap.resize(iNumWGap);
    auto pNode = pWgap->FirstChildElement();
    for (int i = 0; i < iNumWGap; ++i) {
        m_vWGap[i].sName = pNode->Name();
        sValue = pNode->Attribute("X");
        m_vWGap[i].Oc.x = stod(sValue);
        sValue = pNode->Attribute("Y");
        m_vWGap[i].Oc.y = stod(sValue);
        sValue = pNode->Attribute("Z");
        m_vWGap[i].Oc.z = stod(sValue);
        sValue = pNode->Attribute("Ex");
        m_vWGap[i].ei.x = stod(sValue);
        sValue = pNode->Attribute("Ey");
        m_vWGap[i].ei.y = stod(sValue);
        sValue = pNode->Attribute("Ez");
        m_vWGap[i].ei.z = stod(sValue);
        sValue = pNode->Attribute("Z0");
        if (sValue.length() > 0) {
            m_vWGap[i].z0 = stod(sValue);
        } else {
            m_vWGap[i].z0 = 50.0;
        }
        pNode = pNode->NextSiblingElement();
    }
}

// load lump port parameter                         
void DataBase::fn_LoadLumpPort(tinyxml2::XMLElement *pRoot)
{
    auto pLump = pRoot->FirstChildElement("Lumpport");
    if (!pLump) {
        return;
    }
    std::string sValue = pLump->Attribute("Count");
    int iNumLump = stoi(sValue);
    if (iNumLump < 1) {
        return;
    }
    m_vLump.resize(iNumLump);
    auto pNode = pLump->FirstChildElement();
    for (int i = 0; i < iNumLump; ++i) {
        m_vLump[i].sName = pNode->Name();
        sValue = pNode->Attribute("X");
        m_vLump[i].Oc.x = stod(sValue);
        sValue = pNode->Attribute("Y");
        m_vLump[i].Oc.y = stod(sValue);
        sValue = pNode->Attribute("Z");
        m_vLump[i].Oc.z = stod(sValue);
        sValue = pNode->Attribute("Ex");
        m_vLump[i].ei.x = stod(sValue);
        sValue = pNode->Attribute("Ey");
        m_vLump[i].ei.y = stod(sValue);
        sValue = pNode->Attribute("Ez");
        m_vLump[i].ei.z = stod(sValue);
        sValue = pNode->Attribute("Tx");
        m_vLump[i].norm.x = stod(sValue);
        sValue = pNode->Attribute("Ty");
        m_vLump[i].norm.y = stod(sValue);
        sValue = pNode->Attribute("Tz");
        m_vLump[i].norm.z = stod(sValue);
        sValue = pNode->Attribute("Width");
        m_vLump[i].dWidth = stod(sValue);
        sValue = pNode->Attribute("Height");
        m_vLump[i].dHeigh = stod(sValue);
        auto ch = pNode->Attribute("Z0");
        if (ch) {
            m_vLump[i].z0 = stod(string(ch));
        } else {
            m_vLump[i].z0 = 50.0;
        }
        pNode = pNode->NextSiblingElement();
    }
}

// load waveport parameter                          
void DataBase::fn_LoadWavePort(tinyxml2::XMLElement *pRoot)
{
    auto pPort = pRoot->FirstChildElement("Waveport");
    if (!pPort) {
        return;
    }
    std::string sValue = pPort->Attribute("Count");
    int iNumPort = stoi(sValue);
    if (iNumPort < 1) {
        return;
    }
    m_vPort.resize(iNumPort);
    XMLElement* pNode = pPort->FirstChildElement();
    for (int i = 0; i < iNumPort; ++i) {
        m_vPort[i].sName = pNode->Name();
        sValue = pNode->Attribute("X");
        m_vPort[i].Oc.x = stod(sValue);
        sValue = pNode->Attribute("Y");
        m_vPort[i].Oc.y = stod(sValue);
        sValue = pNode->Attribute("Z");
        m_vPort[i].Oc.z = stod(sValue);
        sValue = pNode->Attribute("Ex");
        m_vPort[i].ei.x = stod(sValue);
        sValue = pNode->Attribute("Ey");
        m_vPort[i].ei.y = stod(sValue);
        sValue = pNode->Attribute("Ez");
        m_vPort[i].ei.z = stod(sValue);
        sValue = pNode->Attribute("Tx");
        m_vPort[i].ai.x = stod(sValue);
        sValue = pNode->Attribute("Ty");
        m_vPort[i].ai.y = stod(sValue);
        sValue = pNode->Attribute("Tz");
        m_vPort[i].ai.z = stod(sValue);
        sValue = pNode->Attribute("a");
        m_vPort[i].a = stod(sValue);
        sValue = pNode->Attribute("b");
        m_vPort[i].b = stod(sValue);
        m_vPort[i].sType = pNode->Attribute("Type");
        auto ch = pNode->Attribute("BoundID");
        if (ch) {
            m_vPort[i].iBoundID = stoi(string(ch));
        } else {
            m_vPort[i].iBoundID = -1;
        }
        //sValue = pNode->Attribute("m");
        //if (sValue.length() > 0) m_vPort[i].m = stoi(sValue);
        //sValue = pNode->Attribute("n");
        //if (sValue.length() > 0) m_vPort[i].n = stoi(sValue);
        ch = pNode->Attribute("Z0");
        if (ch) {
            m_vPort[i].z0 = stod(string(ch));
        } else {
            m_vPort[i].z0 = 50.0;
        }
        pNode = pNode->NextSiblingElement();
    }
}

// load equivalent source                           
bool DataBase::fn_LoadEquivSrc(tinyxml2::XMLElement *pRoot)
{
    return true;
}

// set the voltage to source
void DataBase::fn_SetVoltToSrc(std::string &sName, std::vector<double> &vMag, std::vector<double> &vPha)
{
    for (auto &src : m_vWave) {
        if (src.sName == sName) {
            src.vMag = vMag;
            src.vPha = vPha;
            return;
        }
    }
    for (auto &src : m_vWGap) {
        if (src.sName == sName) {
            src.vMag = vMag;
            src.vPha = vPha;
            return;
        }
    }
    for (auto &src : m_vLump) {
        if (src.sName == sName) {
            src.vMag = vMag;
            src.vPha = vPha;
            return;
        }
    }
    for (auto &src : m_vPort) {
        if (src.sName == sName) {
            src.vMag = vMag;
            src.vPha = vPha;
            return;
        }
    }
    for (auto &src : m_vEqui) {
        if (src.sName == sName) {
            src.vMag = vMag;
            src.vPha = vPha;
            return;
        }
    }
}

// set the number of voltage group
void DataBase::fn_SetVoltGroup()
{
    m_iNumVolt = 1;
    for (auto &src : m_vWave) {
        m_iNumVolt = m_iNumVolt > src.vMag.size() ? m_iNumVolt : src.vMag.size();
    }
    for (auto &src : m_vWGap) {
        m_iNumVolt = m_iNumVolt > src.vMag.size() ? m_iNumVolt : src.vMag.size();
    }
    for (auto &src : m_vLump) {
        m_iNumVolt = m_iNumVolt > src.vMag.size() ? m_iNumVolt : src.vMag.size();
    }
    for (auto &src : m_vPort) {
        m_iNumVolt = m_iNumVolt > src.vMag.size() ? m_iNumVolt : src.vMag.size();
    }
    for (auto &src : m_vEqui) {
        m_iNumVolt = m_iNumVolt > src.vMag.size() ? m_iNumVolt : src.vMag.size();
    }
}
